package top.riske.gen3d.util;

import lombok.extern.slf4j.Slf4j;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Slf4j
public class FileUtils {

    /**
     * 根据时间生成文件路径,格式为 /yyyy/MM/dd/fileName
     * @param fileName 文件名
     * @return 文件路径，格式为/yyyy/MM/dd/fileName
     */
    public static String genFilePathByTime(String fileName){
        LocalDateTime now = LocalDateTime.now();
        return "/" + now.getYear()
                + "/" + now.getMonthValue()
                + "/" + now.getDayOfMonth()
                + "/" + fileName;
    }


    public static void main(String[] args) throws IOException {
        List<String> files = getAllFilesInDirectory("E:\\data\\Gen3D\\f4441757-0455-4a86-98ba-8257f23c8793_0");
        System.out.println( files);
    }

    /**
     * 解压 ZIP 文件到与 ZIP 文件同级的目录
     * 例如：/data/files/archive.zip → 解压到 /data/files/archive/
     *
     * @param zipFilePath ZIP 文件的路径
     * @return 解压后的目录路径
     * @throws IOException 解压失败时抛出
     */
    public static String unZipFile(String zipFilePath) throws IOException {
        Path zipPath = Paths.get(zipFilePath);

        // 检查 ZIP 文件是否存在
        if (!Files.exists(zipPath)) {
            throw new FileNotFoundException("ZIP 文件不存在: " + zipFilePath);
        }

        // 检查是否为文件
        if (!Files.isRegularFile(zipPath)) {
            throw new IllegalArgumentException("路径不是文件: " + zipFilePath);
        }

        // 获取 ZIP 文件的父目录（如 /data/files）
        Path parentDir = zipPath.getParent();
        if (parentDir == null) {
            parentDir = Paths.get("."); // 如果没有父目录，使用当前目录
        }

        // 构建解压目录名：去掉 .zip 后缀，加上后缀（如 file.zip → file/）
        String fileName = zipPath.getFileName().toString();
        String dirName;
        if (fileName.toLowerCase().endsWith(".zip")) {
            dirName = fileName.substring(0, fileName.length() - 4);
        } else {
            dirName = fileName + "_extracted";
        }

        Path extractDir = parentDir.resolve(dirName);

        // 创建解压目录
        Files.createDirectories(extractDir);

        // 使用 try-with-resources 自动关闭
        try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zipPath))) {
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                Path entryPath = extractDir.resolve(entry.getName());

                // 防止 ZIP 路径遍历攻击（如 ../../etc/passwd）
                if (!entryPath.normalize().startsWith(extractDir.toAbsolutePath())) {
                    log.warn("非法的 ZIP 条目，跳过: {}", entry.getName());
                    continue;
                }

                if (entry.isDirectory()) {
                    Files.createDirectories(entryPath);
                } else {
                    // 确保父目录存在
                    Files.createDirectories(entryPath.getParent());
                    Files.copy(zis, entryPath, StandardCopyOption.REPLACE_EXISTING);
                }
                log.debug("解压: {}", entry.getName());
            }
        }

        log.info("ZIP 解压完成: {} → {}", zipFilePath, extractDir.toAbsolutePath());
        return extractDir.toAbsolutePath().toString();
    }


    /**
     * 递归获取指定目录下所有的文件（不包含目录），返回路径统一使用 '/' 分隔
     *
     * @param directoryPath 目录路径字符串（支持 Windows/Linux 格式）
     * @return 包含所有文件的路径字符串列表，路径分隔符统一为 '/'（例如：C:/data/file.txt 或 /home/user/file.txt）
     * @throws IOException 如果目录不存在或无法访问
     */
    public static List<String> getAllFilesInDirectory(String directoryPath) throws IOException {
        Path dir = Paths.get(directoryPath);

        // 检查目录是否存在且是目录
        if (!Files.exists(dir)) {
            throw new FileNotFoundException("目录不存在: " + directoryPath);
        }
        if (!Files.isDirectory(dir)) {
            throw new IllegalArgumentException("路径不是目录: " + directoryPath);
        }

        List<String> fileList = new ArrayList<>();

        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (Files.isRegularFile(file)) {
                    // 关键：转换为字符串并统一使用 '/' 分隔符
                    String normalizedPath = file.toString().replace('\\', '/');
                    fileList.add(normalizedPath);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                log.error("无法访问文件: {}, 错误: {}", file, exc.getMessage());
                return FileVisitResult.CONTINUE;
            }
        });

        return fileList;
    }


    /**
     * 根据文件真实路径和基础路径，返回相对于基础路径的子路径（使用正斜杠 '/' 分隔）
     *
     * @param fullPath   文件的真实路径，例如: E:/data/Gen3D/data/2025/9/24/xxx.zip
     * @param basePath   基础路径，例如: E:/data/Gen3D/data
     * @return 相对子路径，例如: /2025/9/24/xxx.zip，如果 basePath 不是前缀则返回 null
     */
    public static String getRelativePath(String fullPath, String basePath) {
        // 使用 Paths 将路径标准化（自动处理 \, \\, / 等）
        Path base = Paths.get(basePath);
        Path full = Paths.get(fullPath);
        // 判断 base 是否是 full 的前缀
        if (!full.startsWith(base)) {
            log.error("基础路径不是真实路径的前缀,基础：{}，真实：{}", basePath, fullPath);
            throw new IllegalArgumentException("基础路径不是真实路径的前缀");
        }
        // 获取相对路径
        Path relative = base.relativize(full);
        // 转为字符串并替换分隔符为正斜杠
        return "/" + relative.toString().replace('\\', '/');
    }

    /**
     * 将任意文件路径（Windows/Linux格式）统一转换为使用正斜杠 '/' 分隔的路径
     * 自动处理 \, \\, /, //, 混合分隔符等情况
     *
     * @param path 输入的文件路径，例如: "E:\\data\\test.txt" 或 "/home/user/test.txt"
     * @return 统一格式后的路径，使用 '/' 分隔，例如: "E:/data/test.txt" 或 "/home/user/test.txt"
     */
    public static String normalizePath(String path) {
        if (path == null || path.trim().isEmpty()) {
            return "";
        }
        // 使用 Paths.get 解析路径（会自动处理各种分隔符）
        Path normalized = Paths.get(path).normalize();
        // 转为字符串并替换所有反斜杠为正斜杠
        return normalized.toString().replace('\\', '/');
    }

}
